{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# PYNQ Microblaze\n",
    "\n",
    "Let's take a look inside the [BaseOverlay class](https://github.com/Xilinx/PYNQ/blob/master/boards/Pynq-Z1/base/base.py) which corresponds to the Overlay below: \n",
    "\n",
    "![](http://pynq.readthedocs.io/en/v2.0/_images/pynqz1_base_overlay.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's load the base overlay and check the IO Processors: iop_arduino, iop_pmoda, and iop_pmodb"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pynq\n",
    "from pynq.overlays.base import BaseOverlay\n",
    "\n",
    "ol = BaseOverlay(\"base.bit\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'audio_direct_0': {'addr_range': 65536,\n",
       "  'driver': pynq.lib.audio.AudioDirect,\n",
       "  'fullpath': 'audio_direct_0',\n",
       "  'gpio': {'sel_direct': {'index': 3,\n",
       "    'pins': {'audio_direct_0/sel_direct', 'audio_path_sel/Dout'},\n",
       "    'state': None}},\n",
       "  'interrupts': {},\n",
       "  'phys_addr': 1136656384,\n",
       "  'state': None,\n",
       "  'type': 'xilinx.com:user:audio_direct:1.1'},\n",
       " 'btns_gpio': {'addr_range': 65536,\n",
       "  'driver': pynq.lib.axigpio.AxiGPIO,\n",
       "  'fullpath': 'btns_gpio',\n",
       "  'gpio': {},\n",
       "  'interrupts': {'ip2intc_irpt': {'controller': 'system_interrupts',\n",
       "    'fullpath': 'btns_gpio/ip2intc_irpt',\n",
       "    'index': 11}},\n",
       "  'phys_addr': 1092681728,\n",
       "  'state': None,\n",
       "  'type': 'xilinx.com:ip:axi_gpio:2.0'},\n",
       " 'iop_arduino/mb_bram_ctrl': {'addr_range': 65536,\n",
       "  'fullpath': 'iop_arduino/mb_bram_ctrl',\n",
       "  'gpio': {},\n",
       "  'interrupts': {},\n",
       "  'phys_addr': 1140850688,\n",
       "  'state': None,\n",
       "  'type': 'xilinx.com:ip:axi_bram_ctrl:4.0'},\n",
       " 'iop_pmoda/mb_bram_ctrl': {'addr_range': 65536,\n",
       "  'fullpath': 'iop_pmoda/mb_bram_ctrl',\n",
       "  'gpio': {},\n",
       "  'interrupts': {},\n",
       "  'phys_addr': 1073741824,\n",
       "  'state': None,\n",
       "  'type': 'xilinx.com:ip:axi_bram_ctrl:4.0'},\n",
       " 'iop_pmodb/mb_bram_ctrl': {'addr_range': 65536,\n",
       "  'fullpath': 'iop_pmodb/mb_bram_ctrl',\n",
       "  'gpio': {},\n",
       "  'interrupts': {},\n",
       "  'phys_addr': 1107296256,\n",
       "  'state': None,\n",
       "  'type': 'xilinx.com:ip:axi_bram_ctrl:4.0'},\n",
       " 'leds_gpio': {'addr_range': 65536,\n",
       "  'driver': pynq.lib.axigpio.AxiGPIO,\n",
       "  'fullpath': 'leds_gpio',\n",
       "  'gpio': {},\n",
       "  'interrupts': {},\n",
       "  'phys_addr': 1092943872,\n",
       "  'state': None,\n",
       "  'type': 'xilinx.com:ip:axi_gpio:2.0'},\n",
       " 'rgbleds_gpio': {'addr_range': 65536,\n",
       "  'driver': pynq.lib.axigpio.AxiGPIO,\n",
       "  'fullpath': 'rgbleds_gpio',\n",
       "  'gpio': {},\n",
       "  'interrupts': {},\n",
       "  'phys_addr': 1092878336,\n",
       "  'state': None,\n",
       "  'type': 'xilinx.com:ip:axi_gpio:2.0'},\n",
       " 'switches_gpio': {'addr_range': 65536,\n",
       "  'driver': pynq.lib.axigpio.AxiGPIO,\n",
       "  'fullpath': 'switches_gpio',\n",
       "  'gpio': {},\n",
       "  'interrupts': {'ip2intc_irpt': {'controller': 'system_interrupts',\n",
       "    'fullpath': 'switches_gpio/ip2intc_irpt',\n",
       "    'index': 12}},\n",
       "  'phys_addr': 1092616192,\n",
       "  'state': None,\n",
       "  'type': 'xilinx.com:ip:axi_gpio:2.0'},\n",
       " 'system_interrupts': {'addr_range': 65536,\n",
       "  'driver': pynq.overlay.DefaultIP,\n",
       "  'fullpath': 'system_interrupts',\n",
       "  'gpio': {},\n",
       "  'interrupts': {},\n",
       "  'phys_addr': 1098907648,\n",
       "  'state': None,\n",
       "  'type': 'xilinx.com:ip:axi_intc:4.1'},\n",
       " 'trace_analyzer_arduino/axi_dma_0': {'addr_range': 65536,\n",
       "  'fullpath': 'trace_analyzer_arduino/axi_dma_0',\n",
       "  'gpio': {},\n",
       "  'interrupts': {'s2mm_introut': {'controller': 'system_interrupts',\n",
       "    'fullpath': 'trace_analyzer_arduino/axi_dma_0/s2mm_introut',\n",
       "    'index': 7}},\n",
       "  'phys_addr': 2151743488,\n",
       "  'state': None,\n",
       "  'type': 'xilinx.com:ip:axi_dma:7.1'},\n",
       " 'trace_analyzer_arduino/trace_cntrl_64_0': {'addr_range': 65536,\n",
       "  'fullpath': 'trace_analyzer_arduino/trace_cntrl_64_0',\n",
       "  'gpio': {},\n",
       "  'interrupts': {},\n",
       "  'phys_addr': 2210398208,\n",
       "  'state': None,\n",
       "  'type': 'xilinx.com:hls:trace_cntrl_64:1.4'},\n",
       " 'trace_analyzer_pmoda/axi_dma_0': {'addr_range': 65536,\n",
       "  'fullpath': 'trace_analyzer_pmoda/axi_dma_0',\n",
       "  'gpio': {},\n",
       "  'interrupts': {'s2mm_introut': {'controller': 'system_interrupts',\n",
       "    'fullpath': 'trace_analyzer_pmoda/axi_dma_0/s2mm_introut',\n",
       "    'index': 6}},\n",
       "  'phys_addr': 2151677952,\n",
       "  'state': None,\n",
       "  'type': 'xilinx.com:ip:axi_dma:7.1'},\n",
       " 'trace_analyzer_pmoda/trace_cntrl_32_0': {'addr_range': 65536,\n",
       "  'fullpath': 'trace_analyzer_pmoda/trace_cntrl_32_0',\n",
       "  'gpio': {},\n",
       "  'interrupts': {},\n",
       "  'phys_addr': 2210463744,\n",
       "  'state': None,\n",
       "  'type': 'xilinx.com:hls:trace_cntrl_32:1.4'},\n",
       " 'video/axi_vdma': {'addr_range': 65536,\n",
       "  'fullpath': 'video/axi_vdma',\n",
       "  'gpio': {},\n",
       "  'interrupts': {'mm2s_introut': {'controller': 'system_interrupts',\n",
       "    'fullpath': 'video/axi_vdma/mm2s_introut',\n",
       "    'index': 1},\n",
       "   's2mm_introut': {'controller': 'system_interrupts',\n",
       "    'fullpath': 'video/axi_vdma/s2mm_introut',\n",
       "    'index': 0}},\n",
       "  'phys_addr': 1124073472,\n",
       "  'state': None,\n",
       "  'type': 'xilinx.com:ip:axi_vdma:6.3'},\n",
       " 'video/hdmi_in/color_convert': {'addr_range': 65536,\n",
       "  'fullpath': 'video/hdmi_in/color_convert',\n",
       "  'gpio': {},\n",
       "  'interrupts': {},\n",
       "  'phys_addr': 1136984064,\n",
       "  'state': None,\n",
       "  'type': 'xilinx.com:hls:color_convert:1.0'},\n",
       " 'video/hdmi_in/frontend/axi_gpio_hdmiin': {'addr_range': 65536,\n",
       "  'fullpath': 'video/hdmi_in/frontend/axi_gpio_hdmiin',\n",
       "  'gpio': {},\n",
       "  'interrupts': {'ip2intc_irpt': {'controller': 'system_interrupts',\n",
       "    'fullpath': 'video/hdmi_in/frontend/axi_gpio_hdmiin/ip2intc_irpt',\n",
       "    'index': 4}},\n",
       "  'phys_addr': 1092747264,\n",
       "  'state': None,\n",
       "  'type': 'xilinx.com:ip:axi_gpio:2.0'},\n",
       " 'video/hdmi_in/frontend/vtc_in': {'addr_range': 65536,\n",
       "  'fullpath': 'video/hdmi_in/frontend/vtc_in',\n",
       "  'gpio': {},\n",
       "  'interrupts': {'irq': {'controller': 'system_interrupts',\n",
       "    'fullpath': 'video/hdmi_in/frontend/vtc_in/irq',\n",
       "    'index': 3}},\n",
       "  'phys_addr': 1136852992,\n",
       "  'state': None,\n",
       "  'type': 'xilinx.com:ip:v_tc:6.1'},\n",
       " 'video/hdmi_in/pixel_pack': {'addr_range': 65536,\n",
       "  'fullpath': 'video/hdmi_in/pixel_pack',\n",
       "  'gpio': {},\n",
       "  'interrupts': {},\n",
       "  'phys_addr': 1136918528,\n",
       "  'state': None,\n",
       "  'type': 'xilinx.com:hls:pixel_pack:1.0'},\n",
       " 'video/hdmi_out/color_convert': {'addr_range': 65536,\n",
       "  'fullpath': 'video/hdmi_out/color_convert',\n",
       "  'gpio': {},\n",
       "  'interrupts': {},\n",
       "  'phys_addr': 1137049600,\n",
       "  'state': None,\n",
       "  'type': 'xilinx.com:hls:color_convert:1.0'},\n",
       " 'video/hdmi_out/frontend/axi_dynclk': {'addr_range': 65536,\n",
       "  'fullpath': 'video/hdmi_out/frontend/axi_dynclk',\n",
       "  'gpio': {},\n",
       "  'interrupts': {},\n",
       "  'phys_addr': 1136721920,\n",
       "  'state': None,\n",
       "  'type': 'digilentinc.com:ip:axi_dynclk:1.0'},\n",
       " 'video/hdmi_out/frontend/hdmi_out_hpd_video': {'addr_range': 65536,\n",
       "  'fullpath': 'video/hdmi_out/frontend/hdmi_out_hpd_video',\n",
       "  'gpio': {},\n",
       "  'interrupts': {'ip2intc_irpt': {'controller': 'system_interrupts',\n",
       "    'fullpath': 'video/hdmi_out/frontend/hdmi_out_hpd_video/ip2intc_irpt',\n",
       "    'index': 5}},\n",
       "  'phys_addr': 1092812800,\n",
       "  'state': None,\n",
       "  'type': 'xilinx.com:ip:axi_gpio:2.0'},\n",
       " 'video/hdmi_out/frontend/vtc_out': {'addr_range': 65536,\n",
       "  'fullpath': 'video/hdmi_out/frontend/vtc_out',\n",
       "  'gpio': {},\n",
       "  'interrupts': {'irq': {'controller': 'system_interrupts',\n",
       "    'fullpath': 'video/hdmi_out/frontend/vtc_out/irq',\n",
       "    'index': 2}},\n",
       "  'phys_addr': 1136787456,\n",
       "  'state': None,\n",
       "  'type': 'xilinx.com:ip:v_tc:6.1'},\n",
       " 'video/hdmi_out/pixel_unpack': {'addr_range': 65536,\n",
       "  'fullpath': 'video/hdmi_out/pixel_unpack',\n",
       "  'gpio': {},\n",
       "  'interrupts': {},\n",
       "  'phys_addr': 1137115136,\n",
       "  'state': None,\n",
       "  'type': 'xilinx.com:hls:pixel_unpack:1.0'}}"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ol.ip_dict"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Some PMODs already have drivers: [list of plug and play PMODs](/tree/base/pmod)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [],
   "source": [
    "from pynq.lib import Pmod_OLED\n",
    "pmod_oled = Pmod_OLED(ol.PMODA)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [],
   "source": [
    "pmod_oled.clear()\n",
    "pmod_oled.write('Welcome to \\n\\nPYNQ!')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's take a look at it's code on [pynq github](https://github.com/Xilinx/PYNQ/tree/master/pynq/lib/pmod)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Hello World on Microblaze\n",
    "IO prrocessors can also be used for running small applications.\n",
    "\n",
    "[IPYthon magic](https://ipython.readthedocs.io/en/stable/interactive/magics.html) allow the execution of Non-Python code in a Python cell."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "from pynq.lib import MicroblazeLibrary"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%microblaze ol.PMODA\n",
    "#include <pyprintf.h>\n",
    "\n",
    "int mb_print(){\n",
    "    pyprintf(\"Hello World!\");\n",
    "    return 0;\n",
    "}\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "mb_print()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Task 1\n",
    "Here you learn how to use provided python libraries.\n",
    "\n",
    "Using the source code for [RGBLED](https://github.com/Xilinx/PYNQ/blob/master/pynq/lib/rgbled.py) write a for loop to change the coloring of your rgb leds between red, blue, and white similar to a police light bar. You can use *time.sleep* as delay between flashes."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import time\n",
    "# write code for RGBLED"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Task 2\n",
    "Write a microblaze code to calculate factorial of an input on PL. Your result should be same as the python code output."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%microblaze ol.PMODB\n",
    "\n",
    "int mb_fact(int in){\n",
    "//write code here\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "inp = 10\n",
    "\n",
    "print('out = {}'.format(mb_fact(inp))) # your function is called here, note the function prototype\n",
    "\n",
    "ff=1\n",
    "for i in range(1,inp+1):\n",
    "    ff = ff*i\n",
    "print('ans = {}'.format(ff))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Task 3\n",
    "Use the [source code](https://github.com/Xilinx/PYNQ/blob/master/pynq/lib/pmod/pmod_oled/src/pmod_oled.c) for OLED_PMOD to learn how to use the GPIO pins.\n",
    "\n",
    "Write two microblaze functions: *mba_send(v)* and *mbb_recv()* to send 1-bit accross the two PMODs *A* and *B*.\n",
    "\n",
    "You need to connect pin 0 of the two PMODs using a jumper wire.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%microblaze ol.PMODA\n",
    "#include <gpio.h>\n",
    "\n",
    "int mba_send(int v){\n",
    "//write code here\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%microblaze ol.PMODB\n",
    "#include <gpio.h>\n",
    "\n",
    "int mbb_recv(){\n",
    "//write code here\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n"
     ]
    }
   ],
   "source": [
    "mba_send(1)\n",
    "print(mbb_recv())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Task 4\n",
    "\n",
    "Read voltages from the Pmod_AD2. **Since there are only 2 Pmod_AD2. Write the code to the best of your ability and ask one of the TA's to check before testing on the Pmod_AD2.**\n",
    "\n",
    "* The first part of this task is to only use the pynq python libraries. You can reference the API [here](https://pynq.readthedocs.io/en/v2.0/pynq_package/pynq.lib/pynq.lib.pmod.html#). *Remember to close the pmod instance*"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [],
   "source": [
    "# write code here"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* For the second part of the task, we'll see how to communicate with the Pmod_AD2 by programming the microblaze in C. While this is more work, most of the PMODS we have available do not have python libraries pre-built so you'll need to search through the documentation and program the microblaze in order to use them.\n",
    "\n",
    "[microblaze libraries for pynq](https://pynq.readthedocs.io/en/latest/pynq_libraries/pynqmb_reference.html)\n",
    "\n",
    "[Pmod_AD2 reference manual](https://reference.digilentinc.com/reference/pmod/pmodad2/reference-manual)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%microblaze base.PMODA\n",
    "#include <i2c.h>\n",
    "#include <pyprintf.h>\n",
    "\n",
    "//TODO: Find the pmod_ad2 address value\n",
    "#define AD2IICAddr         <#>\n",
    "\n",
    "//Configuration\n",
    "#define CH3                 7\n",
    "#define CH2                 6\n",
    "#define CH1                 5\n",
    "#define CH0                 4\n",
    "#define REF_SEL             3\n",
    "#define FLTR                2\n",
    "#define BitTrialDelay       1\n",
    "#define SampleDelay         0\n",
    "\n",
    "#define BitMask             0xFFF\n",
    "\n",
    "float read_i2c() {\n",
    "    \n",
    "    //TODO: open a new i2c device\n",
    "    \n",
    "    unsigned char WriteBuffer[1];    \n",
    "    unsigned char cfgValue = (1 << CH3)   |\n",
    "               (1 << CH2)                 |\n",
    "               (1 << CH1)                 |\n",
    "               (1 << CH0)                 |\n",
    "               (0 << REF_SEL)             |\n",
    "               (0 << FLTR)                |\n",
    "               (0 << BitTrialDelay)       |\n",
    "               (0 << SampleDelay);\n",
    "    WriteBuffer[0]=cfgValue;\n",
    "    //TODO: write the configuration to the pmod (1 byte)\n",
    "    \n",
    "    //Receiving data.\n",
    "    unsigned char rcvbuffer[2];\n",
    "    int rxData;\n",
    "    //TODO: read from the pmod and format the raw data (2 bytes)\n",
    "    // The first byte is MSB, while the second byte is LSB\n",
    "    rxData = //;\n",
    "    \n",
    "    \n",
    "    //Format as a voltage\n",
    "    int raw = (rxData & BitMask);    \n",
    "    return (float)(raw * 2.00 / 4096.0); // 2.0 V is the reference voltage for the AD2 Pmod.\n",
    "}"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
